﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LiveGame
{
    public class Board : IEnumerable, IDataStructure<IPieces>
    {
        public class Columns : IEnumerable< IPieces >, IDataStructure<IPieces>
        {
            private readonly IPieces[] columns;

            internal Columns( IPieces[] columns )
            {
                this.columns = columns;
            }

            public int Length
            {
                get { return this.columns.Length; }
            }

            public void Add( IPieces item )
            {
                throw new NotImplementedException();
            }

            public IPieces this[int columnIndex]
            {
                get { return this.columns[ columnIndex ]; }
            }

            public IEnumerator< IPieces > GetEnumerator()
            {
                for( int indexColumn = 0; indexColumn < this.columns.Length; indexColumn++ )
                    yield return this[ indexColumn ];
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }

        private IPieces[][] board;

        public Board( int numberOfRows, int numberOfColumns )
        {
            this.SetUpBoard( numberOfRows, numberOfColumns );
        }

        public int Length
        {
            get { return this.board.Length; }
        }

        public void Add( IPieces piece )
        {
            if( piece == null )
                throw new ArgumentNullException( typeof( IPieces ).ToString() );

            if( piece.Row < 0 || piece.Row >= this.board.Length )
                throw new ArgumentOutOfRangeException( "piece.Row" );

            if( piece.Column < 0 || piece.Column >= this.board [ 0 ].Length )
                throw new ArgumentOutOfRangeException( "piece.Column" );

            if( this.board [ piece.Row ] [ piece.Column ] != null )
                throw new ArgumentException( "Unable to add new piece since the coordinate you are referring to has been allocated by other piece." );

            this.board [ piece.Row ] [ piece.Column ] = piece;
        }

        public Columns this[int rowIndex]
        {
            get { return new Columns( this.board[ rowIndex ] ); }
        }

        private void SetUpBoard( int numberOfRows, int numberOfColumns )
        {
            this.board = new IPieces[numberOfRows][];

            for( int rowIndex = 0; rowIndex < this.board.Length; rowIndex++ )
                this.board[rowIndex] = new IPieces[numberOfColumns];
        }
        
        public IEnumerator GetEnumerator()
        {
            for (int rowIndex = 0; rowIndex < this.board.Length; rowIndex++)
            {
                yield return this[rowIndex];
            }
        }
    }
}
